home *** CD-ROM | disk | FTP | other *** search
- { This is an example of exporting your own compression algorithm into ARCDIB
- using a Turbo Pascal DLL. You can use this code as a shell by replacing
- the "YouCompress" and "YourDeCompress" functions with your own algorithms
- for compression and decompression respectively. The function exported by
- the DLL is "MyComp".
-
- function MyComp(var IMAGEHANDLE: THandle;
- var BITSSIZE: LongInt;
- COMPRESS: Boolean): Boolean ; export;
-
- Its name and parameters must not change since ARCDIB expects it that way.
- As you can see, the function returns TRUE or FALSE depending on its sucess
- - determined by you. The three parameters are:
-
- IMAGEHANDLE: a Windows Global Handle to a memory block containing either
- the uncompressed or compressed bytes of the bitmap image.
-
- BITSSIZE: the size of the bitmap bytes ("bits") before being
- compressed and the size of the compressed bits when
- expanding.
-
- COMPRESS: TRUE if compressing, FALSE if decompressing. If compressing,
- IMAGEHANDLE refers to a block of uncompressed bitmap "bits"
- - the same as to "bits" of a Windows DIB. If decompressing,
- then IMAGEHANDLE refers to the block of memory returned as
- a result of a previous compression.
-
- THE CONCEPT IS THIS:
- Upon entry into "MyComp" you obtain a pointer to the memory block referred
- to by IMAGEHANDLE. You then create another global Handle of size BITSSIZE
- to use as output of your compression/decompression routine. Obtain a
- pointer to this NewHandle with GlobalLock. Then, you pass each byte
- in IMAGEHANDLE (in this case, one at a time) to either YourCompress or
- YourDeCompress routines depending on the COMPRESS flag. In each of those
- routines, you write the output to the new memory block you created
- referred to by NewHandle. Finally, you reallocate NewHandle to the size
- resulting from the compression/decompression (ie keep track of the number
- of bytes written) and get rid the passed in IMAGEHANDLE with GlobalFree
- and reassign it to Newhandle. Always pass the resulting size of the
- compressed (or expanded) bytes in BITSSIZE!
- Keep the following in mind:
-
- 1. This alorithm ASSUMES the result of the compression will require
- a smaller block of memory than the original. For decompression,
- the result should equal the original (obiviously) and the
- GlobalReAlloc call is actually redundant because in both cases
- you create Newhandle using the original (uncompressed) size.
-
- 2. You must keep track of the number of bytes written to the new
- handle in order to determine its new size for reallocation.
-
- 3. Don't forget to "unlock" the new handle before returning from
- the function.
-
- 4. If the function returns FALSE, ARCDIB flags the bitmap as being
- in compressed form and will therefore call MyComp again to
- uncompress the "bits" before displaying.
-
- 5. If you return FALSE during compression, ARCDIB will just
- assume something went wrong in your compression and EXPECTS
- IMAGEHANDLE refer to the same block of uncompressed bytes that
- it did before the call! This could be disastorous if you somehow
- corrupt the original data so be careful not to. Worse yet, on
- decompression, returning FALSE leaves ARCDIB on a limb because,
- presumably, it passed in successfully compressed data and you
- are now telling it that there's no way back...we're doomed.
-
- 6. Keep in mind that if the size of the bitmap is greater that
- 64K, you must make your code aware of the segment boundries
- that you'll eventually cross reading and (possibly) writing
- from/to the memory blocks. This is illustrated in the example
- by creating a variant record type for a special far pointer
- that can be safely incremented using a Windows call to AHINC().
-
- ***** Thanks to Tom Swam (the Charles Petzold of TPW) and his book
- "Turbo Pascal for Windows 3.0 Programming" for this and MANY
- other useful tricks.
-
- 6. When compressing/decompressing a bitmap in ARCDIB, a status
- box appears showing percent completion. In your case, I have
- no way of knowing this info so the box just kind of sits
- there and says "Please wait..". In the future, I'll provide
- some type of Callback function so that you can update the
- status yourself - or least the OPTION to, since most compression
- purest loaf the idea of delaying their algorithm unecessarily.
-
- 7. Again, the library (DLL) name MUST remain "YourComp" and the
- compression function name MUST remain "MyComp" with the SAME
- parameters and exported index.
-
- Sine Labore Nihil...
-
-
- Brendan Daunt
- BETTER MAPS
- (619) 598-1323
- 76307,2411
- }
-
- {***************************************************************************}
- library YourComp; { Don't change this name }
-
- uses WinTypes, WinProcs;
-
- { Windows function for calculating pointer offsets safely }
- Procedure AHIncr; far; external 'KERNEL' index 114;
-
- { Variant record type for a far pointer to step through memory blocks that
- may cross segment boundries. }
- Type
- LongType = record
- case word of
- 0: (Ptr: Pointer);
- 1: (Long: LongInt);
- 2: (Lo: Word; Hi: Word);
- end;
-
- { Global variables }
- Var h, { Temporary handle }
- NewHandle: THandle; { New handle refers to compressed "bits" }
- OldBits, { Pointer to memory block in IMAGEHANDLE }
- NewBits : Pointer; { Pointer to memory block in NewHandle }
- NewSize : LongInt; { Resulting size of NewHandle after compression }
-
- { These are dummy procedures (stubs) provided to illustrate how you might
- implement your own compress/decompress algorithms.
-
- They are called from the exported function "MyComp" with a Byte type
- parameter which represents an uncompressed/compressed byte in the
- original IMAGEHANDLE passed to "MyComp".
-
- Be sure to write the output of either function to the global memory
- block in NewHandle and also keep track of the numbers of bytes written }
-
- Var
- ToBits,
- ToStart,
- ToAddr : LongType; { Special far pointer records }
-
- procedure YourCompress(InByte: Byte);
- {}
- Begin
- { ...compress InByte somehow }
-
- ToAddr.Hi := ToBits.Hi + ( ToStart.Hi * Ofs(AHIncr));
- ToAddr.Lo := ToStart.LO;
- Byte(ToAddr.Ptr^) := InByte;
- Inc(ToStart.Long);
-
- Inc(NewSize);
- End;
-
- procedure YourDeCompress(InByte: Byte);
- {}
- Begin
- { ...decompress InByte somehow }
-
- ToAddr.Hi := ToBits.Hi + ( ToStart.Hi * Ofs(AHIncr));
- ToAddr.Lo := ToStart.LO;
- Byte(ToAddr.Ptr^) := InByte;
- Inc(ToStart.Long);
-
- Inc(NewSize);
- End;
-
-
- { This is the only function exported by YourComp.DLL - header and
- results must remain the same (see above). }
-
- function MyComp(var IMAGEHANDLE: THandle;
- var BITSSIZE: LongInt;
- COMPRESS: Boolean) : Boolean ; export;
- {}
- Var
- OneByte : Byte; { Holds a byte to be compressed/decompressed }
- ImageSize, { Size of IMAGEHANDLE }
- OldPtrOffSet: LongInt; { Pointer offset into IMAGEHANDLE }
- FromBits,
- FromStart,
- FromAddr : LongType; { Special far pointer records }
-
- Begin
- MessageBox(GetActiveWindow, 'Dummy compress DLL for instructional purposes only.', 'YourComp.DLL', mb_IconExclamation);
- MyComp := False;
- NewSize := 0; { Contains the number of bytes written to NewHandle }
-
- { Get a pointer to the original handle }
- OldBits := GlobalLock(IMAGEHANDLE);
- If OldBits = nil Then
- Begin
- MessageBox(GetActiveWindow, 'OldBits = nil', 'MyComp ERROR',
- mb_TaskModal or mb_Ok);
- Exit;
- End;
-
- { Create new memory block (NewHandle) - same size as uncompressed block }
- NewHandle := GlobalAlloc(gmem_Moveable or gmem_ZeroInit, BITSSIZE);
- If NewHandle = 0 Then
- Begin
- MessageBox(GetActiveWindow, 'NewHandle = 0', 'MyComp ERROR',
- mb_TaskModal or mb_Ok);
- Exit;
- End;
-
- { Get a pointer to the new handle }
- NewBits := GlobalLock(NewHandle);
- If NewBits = nil Then
- Begin
- MessageBox(GetActiveWindow, 'NewBits = nil', 'MyComp ERROR',
- mb_TaskModal or mb_Ok);
- GlobalFree(NewHandle);
- Exit;
- End;
-
- FromStart.Long := 0; { Initial pointer offset into IMAGEHANDLE }
- FromBits.Ptr := OldBits; { Use LongType pointer for segment "awareness" }
-
- ToStart.Long := 0; { Initial pointer offset into NewHandle }
- ToBits.Ptr := NewBits; { Use LongType pointer for segment "awareness" }
-
- { Process each byte in IMAGEHANDLE }
- ImageSize := GlobalSize(IMAGEHANDLE);
- For OldPtrOffset := 0 to ImageSize-1 Do
- Begin
- { Calculate the pointer offset }
- FromAddr.Hi := FromBits.Hi + ( FromStart.Hi * Ofs(AHIncr));
- FromAddr.Lo := FromStart.LO;
-
- { Get a byte from the original memory block in IMAGEHANDLE }
- OneByte := Byte(FromAddr.Ptr^);
-
- { Now call your compression or decompression routine with OneByte }
- If Compress Then
- YourCompress(OneByte) { procedure of your choice for compression }
- Else
- YourDeCompress(OneByte); { procedure of your choice for decompression }
-
- { Increment the pointer offset }
- Inc(FromStart.Long);
- End; { For each byte in IMAGEHANDLE }
-
- { Unlock the NewHandle and attempt to reallocate it with new size }
- GlobalUnlock(NewHandle);
- h := GlobalReAlloc(NewHandle, NewSize, gmem_Moveable or gmem_ZeroInit);
- if (h <> 0) Then
- Begin
- GlobalUnlock(IMAGEHANDLE);
- GlobalFree(IMAGEHANDLE); { Get rid of original handle to "bits" }
- NewHandle := h; { Assign NewHandle to reallocated block}
- End
- Else { GlobalReAlloc failed - abort }
- Begin
- GlobalFree(NewHandle); { Free the new handle }
- MessageBox(GetActiveWindow, 'Could realloc NewHandle', 'MyComp ERROR',
- mb_TaskModal or mb_Ok);
- Exit;
- End;
-
- { Success }
- BITSSIZE := NewSize;
- ImageHandle := NewHandle;
- MyComp := True;
-
- End; { MyComp }
-
- {- List exported routines }
-
- exports
-
- MyComp index 3; { Export MyComp with index of 3 }
-
- BEGIN
- END. { YourComp DLL }
-
-
-